﻿using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using UnityEditor;
using UnityEngine;

public class BuildAssetBundle : EditorWindow
{
    public static Dictionary<string, BundleGroup> m_BundleList = new Dictionary<string, BundleGroup>();

    static BundleGroup m_CurrentSelected = null;

    Vector2 m_Scroll = Vector2.zero;

    const string notification = "1.Add: Create New AssetBundle,and collect assets.\n2.Load: Load BundleData and show bundle info."
        + "\n3.Save: Save AssetBundle info to xml,and next time can load from xml." + "\n4.Export: Export LoadAsset on the basis of bundleList." +
        "\n5.Build: Tool will build all AssetBundle depend on xml";
    const string waring = "Every AssetBundle only can dependency on one other AssetBundle!(this problem can not resolve)";

    bool isShowNotify = true;

    static bool isBuildAll = true;

    static TargetPlatform m_TargetPlatform = TargetPlatform.StandaloneWindow;

    static string m_RootDirectory = "";

    static bool m_ShowFloderStyle = false;

    static Dictionary<TargetPlatform, string> m_PlatformRootDic = new Dictionary<TargetPlatform, string>();

    public static List<string> m_OutPutFolder = new List<string>();

    static List<bool> m_FloderFlodOut = new List<bool>();

    public enum TargetPlatform : int
    {
        StandaloneWindow = BuildTarget.StandaloneWindows,
        //StandaloneOSX = BuildTarget.StandaloneOSXUniversal,
        Android = BuildTarget.Android,
        iPhone = BuildTarget.iOS,
        //WebPlayer = BuildTarget.WebPlayer,
    }

    [MenuItem("Tools/BuildAssetBundle")]
    static void CallBuildWindow()
    {
        BuildAssetBundle window = EditorWindow.GetWindow<BuildAssetBundle>();
        window.maxSize = new Vector2(505f, 1000f);
        window.minSize = new Vector2(505f, 100f);
        window.title = "Bundle Tool";
        window.autoRepaintOnSceneChange = true;
        if (string.IsNullOrEmpty(m_RootDirectory))
        {
            string fullPath = Application.dataPath + "/../../AssetBundle/";
            m_RootDirectory = fullPath + m_TargetPlatform.ToString();
        }

#if UNITY_STANDALONE_WIN
        m_TargetPlatform = TargetPlatform.StandaloneWindow;
#elif UNITY_STANDALONE_OSX
        m_TargetPlatform = TargetPlatform.StandaloneOSX;
#elif UNITY_ANDROID
        m_TargetPlatform = TargetPlatform.Android;
#elif UNITY_IPHONE
        m_TargetPlatform = TargetPlatform.iPhone;
#elif UNITY_WEBPLAYER
        m_TargetPlatform = TargetPlatform.WebPlayer;
#endif

        if (m_PlatformRootDic.ContainsKey(m_TargetPlatform))
        {
            m_RootDirectory = m_PlatformRootDic[m_TargetPlatform];
        }
    }

    void OnGUI()
    {
        EditorGUIUtility.labelWidth = 80f;

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("AssetBundleBuilder");
        if (GUILayout.Button("Refresh"))
        {
            Refresh();
        }

        if (GUILayout.Button("?", GUILayout.Width(20f)))
        {
            isShowNotify = !isShowNotify;
        }
        EditorGUILayout.EndHorizontal();

        if (isShowNotify)
        {
            EditorGUILayout.HelpBox(notification, MessageType.Info, true);
        }

        DrawSeparator();
        EditorGUILayout.BeginHorizontal();
        if (GUILayout.Button("Add", GUILayout.Width(84f), GUILayout.Height(50f)))
        {
            m_CurrentSelected = null;
            //BundleGroupEditor.NewBundle(null);
        }

        if (GUILayout.Button("Load", GUILayout.Width(84f), GUILayout.Height(50f)))
        {
            LoadBundleInfo();
            SetIsAllBuild();
            Refresh();
            FilterBundlePath();
            GUI.FocusControl("Browse");
        }

        if (GUILayout.Button("Save", GUILayout.Width(84f), GUILayout.Height(50f)))
        {
            SaveBundleInfo();
        }

        if (GUILayout.Button("Export", GUILayout.Width(84f), GUILayout.Height(50f)))
        {
            SaveLoadAsset();
        }

        if (GUILayout.Button("Build", GUILayout.Width(84f), GUILayout.Height(50f)))
        {
            Build();
            Refresh();
        }
        else
        {
            EditorGUILayout.EndHorizontal();
        }

        GUILayout.Space(4f);
        HighlightLine(Color.black, 22f);
        EditorGUILayout.LabelField("Bundle Setting", EditorStyles.boldLabel);
        GUILayout.Space(4f);
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Target Platform *");
        m_TargetPlatform = (TargetPlatform)EditorGUILayout.EnumPopup(m_TargetPlatform);
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Target Directory *");
        m_RootDirectory = EditorGUILayout.TextField(m_RootDirectory);
        GUI.SetNextControlName("Browse");
        if (GUILayout.Button("Browse", GUILayout.Width(60f)))
        {
            string path = EditorUtility.OpenFolderPanel("Select floder for building bundles", m_RootDirectory, "");
            m_RootDirectory = path.Length > 0 ? path : m_RootDirectory;
            GUI.FocusControl("Browse");
        }
        EditorGUILayout.EndHorizontal();

        DrawSeparator();
        HighlightLine(Color.black, 20f);
        EditorGUILayout.BeginHorizontal();

        bool isAllbuild = EditorGUILayout.Toggle(isBuildAll, GUILayout.Width(20f));
        if (isAllbuild != isBuildAll)
        {
            isBuildAll = isAllbuild;
            SetIsBuild(isBuildAll);
        }
        if (GUILayout.Button("Bundle", EditorStyles.toolbarPopup, GUILayout.Width(120f)))
        {
            SortByBundleName();
        }
        if (GUILayout.Button("Floder", EditorStyles.toolbarPopup, GUILayout.Width(120f)))
        {
            SortByFloderName();
        }
        if (GUILayout.Button("Dependency", EditorStyles.toolbarPopup, GUILayout.Width(120f)))
        {
            SortByDependence();
        }
        if (GUILayout.Button(m_ShowFloderStyle == true ? "★OnlyFloder" : "●OnlyFile", EditorStyles.toolbarPopup, GUILayout.Width(120f)))
        {
            m_ShowFloderStyle = !m_ShowFloderStyle;
        }

        GUILayout.Label("", EditorStyles.toolbarPopup, GUILayout.Width(120f));
        EditorGUILayout.EndHorizontal();
        DrawSeparator();

        if (m_ShowFloderStyle)
        {
            OnlyFloderShow();
        }
        else
        {
            OnlyFileShow();
        }

        DrawSeparator();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("BundleNumbers:", EditorStyles.boldLabel, GUILayout.Width(110f));
        EditorGUILayout.LabelField(m_BundleList.Count.ToString(), EditorStyles.boldLabel);
        EditorGUILayout.EndHorizontal();
    }

    #region OnlyFloderShowStyle
    private void OnlyFloderShow()
    {
        m_Scroll = EditorGUILayout.BeginScrollView(m_Scroll);
        for (int i = 0; i < m_OutPutFolder.Count; i++)
        {
            if (i > 0)
            {
                GUILayout.Space(10f);
            }

            HighlightLine(Color.black, 20f);
            if (m_FloderFlodOut[i] = EditorGUILayout.Foldout(m_FloderFlodOut[i], m_OutPutFolder[i]))
            {
                foreach (BundleGroup bundle in new List<BundleGroup>(m_BundleList.Values))
                {
                    if (!bundle.m_BundlePath.Equals(m_OutPutFolder[i]))
                        continue;

                    ShowBundleUI(bundle);
                }
            }
        }


        EditorGUILayout.EndScrollView();
    }
    #endregion

    #region OnlyFileShowStyle
    private void OnlyFileShow()
    {
        m_Scroll = EditorGUILayout.BeginScrollView(m_Scroll);
        foreach (BundleGroup bundle in new List<BundleGroup>(m_BundleList.Values))
        {
            ShowBundleUI(bundle);
        }
        EditorGUILayout.EndScrollView();
    }
    #endregion

    #region ShowSingleBundleUI
    void ShowBundleUI(BundleGroup bundle)
    {
        Color color = Color.white;
        if (m_CurrentSelected != null && m_CurrentSelected == bundle)
        {
            color = Color.blue;
            bundle.m_IsError = false;
        }
        else if (bundle.m_IsError)
        {
            color = Color.red;
        }

        HighlightLine(color, 25f);
        EditorGUILayout.BeginHorizontal();
        if (m_ShowFloderStyle)
        {
            GUILayout.Space(15f);
        }

        bool isbuild = EditorGUILayout.Toggle(bundle.m_IsBuild, GUILayout.Width(10f));
        if (isbuild != bundle.m_IsBuild)
        {
            bundle.m_IsBuild = isbuild;
            SetIsAllBuild();
        }
        GUILayout.Toggle(bundle.m_IsExsit, "", EditorStyles.radioButton, GUILayout.Width(10f));
        EditorGUILayout.LabelField(bundle.m_BundleName, GUILayout.Width(120f));
        EditorGUILayout.LabelField(bundle.m_BundlePath, GUILayout.Width(120f));
        if (GUILayout.Button("Edit/Show", EditorStyles.boldLabel, GUILayout.Width(80f)))
        {
            BundleDependencies.ShowDependency(bundle);
            m_CurrentSelected = bundle;
        }
        if (GUILayout.Button("Delete", GUILayout.Width(50f)))
        {
            Remove(bundle.GetId());
            SetIsAllBuild();
        }
        if (GUILayout.Button("Info", GUILayout.Width(50f)))
        {
            BundleGroupTools.NewBundle(bundle);
            m_CurrentSelected = bundle;
        }
        EditorGUILayout.EndHorizontal();
    }
    #endregion

    void SetIsBuild(bool isbuild)
    {
        if (m_BundleList.Count == 0)
            return;

        foreach (BundleGroup bundle in m_BundleList.Values)
        {
            bundle.m_IsBuild = isbuild;
        }
    }

    void SetIsAllBuild()
    {
        if (m_BundleList.Count == 0)
            return;

        foreach (BundleGroup bundle in m_BundleList.Values)
        {
            if (bundle.m_IsBuild == false)
            {
                isBuildAll = false;
                return;
            }
        }

        isBuildAll = true;
    }

    private void LoadBundleInfo()
    {
        if (m_BundleList.Count != 0)
        {
            int options = EditorUtility.DisplayDialogComplex("Do you want to replace or append?",
                "Are you sure replace or append?", "Replace", "Append", "Cancel");
            if (options == 0)
            {
                m_BundleList.Clear();
                Load();
            }
            else if (options == 1)
            {
                Load();
            }
            else if (options == 2)
            {
                return;
            }
        }
        else
        {
            Load();
        }
    }

    private void SaveBundleInfo()
    {
        if (m_BundleList.Count == 0)
            return;

        if (EditorUtility.DisplayDialog("Do you want to save the changes you made?",
            "You will replace default data", "Replace", "Cancel"))
        {
            Save();
        }
    }

    BuildAssetBundleOptions options = BuildAssetBundleOptions.CollectDependencies |
        BuildAssetBundleOptions.CompleteAssets |
        BuildAssetBundleOptions.DeterministicAssetBundle;

    List<BundleGroup> buildedbundles = null;
    private void Build()
    {
        if (m_BundleList.Count == 0)
            return;

        if (string.IsNullOrEmpty(m_RootDirectory))
        {
            string fullPath = Application.dataPath + "/../../AssetBundle/";
            m_RootDirectory = fullPath + m_TargetPlatform.ToString();
        }

        buildedbundles = new List<BundleGroup>();

        foreach (BundleGroup bundle in m_BundleList.Values)
        {
            if (bundle.m_IsBuild == false)
                continue;

            if (buildedbundles.Contains(bundle))
                continue;

            BundleGroup bundlegroup = HightestDepend(bundle);
            BuildBundle(bundlegroup);
        }
    }

    void BuildBundle(BundleGroup bundle)
    {
        if (bundle.m_AssetArray.Count == 0)
        {
            bundle.m_IsError = true;
        }

        BuildPipeline.PushAssetDependencies();
        if (bundle.m_BundleType == BundleType.StreamedAssets)
        {
            BuildPipeline.BuildAssetBundle(bundle.m_AssetArray[0], bundle.m_AssetArray.ToArray(),
                GetPath(bundle), options, (BuildTarget)((int)m_TargetPlatform));

            buildedbundles.Add(bundle);
        }
        else if (bundle.m_BundleType == BundleType.StreamedScenes)
        {
            string path = AssetDatabase.GetAssetOrScenePath(bundle.m_AssetArray[0]);
            string[] leves = { path };
            BuildPipeline.BuildStreamedSceneAssetBundle(leves,
                GetPath(bundle), (BuildTarget)((int)m_TargetPlatform));

            buildedbundles.Add(bundle);
        }

        foreach (BundleGroup bundlegroup in m_BundleList.Values)
        {
            if (bundle == bundlegroup)
                continue;

            if (!IsNeedBuild(bundlegroup) && !bundlegroup.m_IsBuild)
                continue;

            if (bundlegroup.m_Dependencies.Equals(bundle.GetId()))
            {
                BuildBundle(bundlegroup);
            }
        }

        BuildPipeline.PopAssetDependencies();
    }

    bool IsNeedBuild(BundleGroup bundle)
    {
        foreach (BundleGroup bundlegroup in m_BundleList.Values)
        {
            if (bundlegroup.m_Dependencies.Equals(bundle.GetId()))
            {
                if (bundlegroup.m_IsBuild)
                    return true;

                return IsNeedBuild(bundlegroup);
            }
        }

        return false;
    }

    BundleGroup HightestDepend(BundleGroup bundle)
    {
        if (bundle == null || string.IsNullOrEmpty(bundle.m_Dependencies))
            return bundle;

        BundleGroup dependbundle = m_BundleList[bundle.m_Dependencies];

        return HightestDepend(dependbundle);
    }

    string GetPath(BundleGroup bundle)
    {
        string parentpath = m_RootDirectory + "/" + bundle.m_BundlePath;

        if (!Directory.Exists(parentpath))
        {
            Directory.CreateDirectory(parentpath);
        }

        return parentpath + "/" + bundle.m_BundleName + ".unity3d";
    }

    void Remove(string id)
    {
        if (m_BundleList.ContainsKey(id))
        {
            BundleGroup curbundle = m_BundleList[id];
            DeleteBundleFile(curbundle);
            m_BundleList.Remove(id);

            if (m_BundleList.Count > 0)
            {
                foreach (BundleGroup bundle in m_BundleList.Values)
                {
                    if (bundle.m_Dependencies.Equals(id))
                    {
                        bundle.m_Dependencies = "";
                    }
                }
            }
            FilterBundlePath();
            FlodOutFloder(curbundle);
        }
    }

    void DeleteBundleFile(BundleGroup bundle)
    {
        if (bundle == null)
            return;

        string path = GetPath(bundle);
        if (File.Exists(path))
        {
            if (EditorUtility.DisplayDialog("Do you want to delete bundle file on disk",
            "It will can not be recovered", "Yes", "No"))
            {
                File.Delete(path);
            }
        }
    }

    static public void AddBundle(BundleGroup bundle)
    {
        if (m_CurrentSelected != null)
        {
            string id = m_CurrentSelected.GetId();
            if (m_BundleList.ContainsKey(id))
            {
                m_BundleList.Remove(id);
            }
        }

        string newid = bundle.GetId();
        if (m_BundleList.ContainsKey(newid))
        {
            m_BundleList[newid] = bundle;
        }
        else
        {
            m_BundleList.Add(newid, bundle);
        }

        FilterBundlePath();
        FlodOutFloder(bundle);
    }

    string GetFloder(string path)
    {
        string floder = "";
        string[] spilts = path.Split('/');
        if (spilts != null && spilts.Length > 0)
        {
            floder = spilts[spilts.Length - 1];
        }
        else
        {
            floder = path;
        }

        return floder;
    }

    int sortBundleName = -1;
    void SortByBundleName()
    {
        if (m_BundleList.Count == 0)
            return;

        sortBundleName = sortBundleName * -1;
        List<BundleGroup> ls = new List<BundleGroup>(m_BundleList.Values);
        ls.Sort(delegate(BundleGroup a, BundleGroup b)
        {
            return a.m_BundleName.CompareTo(b.m_BundleName) * sortBundleName;
        });
        m_BundleList.Clear();
        string id = "";
        foreach (BundleGroup bundle in ls)
        {
            id = bundle.GetId();
            m_BundleList.Add(id, bundle);
        }
    }

    int sortFloderName = -1;
    void SortByFloderName()
    {
        if (m_BundleList.Count == 0)
            return;

        sortFloderName = sortFloderName * -1;
        List<BundleGroup> ls = new List<BundleGroup>(m_BundleList.Values);
        ls.Sort(delegate(BundleGroup a, BundleGroup b)
        {
            return a.m_BundlePath.CompareTo(b.m_BundlePath) * sortFloderName;
        });
        m_BundleList.Clear();
        string id = "";
        foreach (BundleGroup bundle in ls)
        {
            id = bundle.GetId();
            m_BundleList.Add(id, bundle);
        }

        m_OutPutFolder.Sort(delegate(string a, string b)
        {
            return a.CompareTo(b) * sortFloderName;
        });
    }

    int sortDependence = -1;
    void SortByDependence()
    {
        if (m_BundleList.Count == 0)
            return;

        sortDependence = sortDependence * -1;
        List<BundleGroup> ls = new List<BundleGroup>(m_BundleList.Values);
        ls.Sort(delegate(BundleGroup a, BundleGroup b)
        {
            return a.m_Dependencies.CompareTo(b.m_Dependencies) * sortDependence;
        });
        m_BundleList.Clear();
        string id = "";
        foreach (BundleGroup bundle in ls)
        {
            id = bundle.GetId();
            m_BundleList.Add(id, bundle);
        }
    }

    static void FilterBundlePath()
    {
        m_OutPutFolder.Clear();
        m_FloderFlodOut.Clear();

        Dictionary<string, BundleGroup> bundleList = BuildAssetBundle.m_BundleList;
        if (bundleList.Count > 0)
        {
            foreach (BundleGroup bundle in bundleList.Values)
            {
                if (!m_OutPutFolder.Contains(bundle.m_BundlePath))
                {
                    m_OutPutFolder.Add(bundle.m_BundlePath);
                    m_FloderFlodOut.Add(false);
                }
            }
        }
    }

    static void FlodOutFloder(BundleGroup bundle)
    {
        for (int i = 0; i < m_OutPutFolder.Count; i++)
        {
            if (bundle.m_BundlePath == m_OutPutFolder[i])
            {
                m_FloderFlodOut[i] = true;
            }
        }
    }

    #region CustomSkin
    static Texture2D mGradientTex;

    static public Texture2D blankTexture
    {
        get
        {
            return EditorGUIUtility.whiteTexture;
        }
    }

    static public Texture2D gradientTexture
    {
        get
        {
            if (mGradientTex == null) mGradientTex = CreateGradientTex();
            return mGradientTex;
        }
    }

    static public void DrawSeparator()
    {
        DrawSeparator(12f);
    }

    static public void DrawSeparator(float height)
    {
        GUILayout.Space(height);

        if (Event.current.type == EventType.Repaint)
        {
            Texture2D tex = blankTexture;
            Rect rect = GUILayoutUtility.GetLastRect();
            GUI.color = new Color(0f, 0f, 0f, 0.25f);
            GUI.DrawTexture(new Rect(0f, rect.yMin + 6f, Screen.width, 4f), tex);
            GUI.DrawTexture(new Rect(0f, rect.yMin + 6f, Screen.width, 1f), tex);
            GUI.DrawTexture(new Rect(0f, rect.yMin + 9f, Screen.width, 1f), tex);
            GUI.color = Color.white;
        }
    }

    static Texture2D CreateGradientTex()
    {
        Texture2D tex = new Texture2D(1, 16);
        tex.name = "[Generated] Gradient Texture";
        tex.hideFlags = HideFlags.DontSave;

        Color c0 = new Color(1f, 1f, 1f, 0f);
        Color c1 = new Color(1f, 1f, 1f, 0.6f);

        for (int i = 0; i < 16; ++i)
        {
            float f = Mathf.Abs((i / 15f) * 2f - 1f);
            f *= f;
            tex.SetPixel(0, i, Color.Lerp(c0, c1, f));
        }

        tex.Apply();
        tex.filterMode = FilterMode.Bilinear;
        return tex;
    }

    static public void HighlightLine(Color c, float height, float width)
    {
        Rect rect = GUILayoutUtility.GetRect(width - 16f, height);
        GUILayout.Space(-height);
        c.a *= 0.3f;
        GUI.color = c;
        GUI.DrawTexture(rect, gradientTexture);
        c.r *= 0.5f;
        c.g *= 0.5f;
        c.b *= 0.5f;
        GUI.color = c;
        GUI.DrawTexture(new Rect(rect.x, rect.y + 1f, rect.width, 1f), blankTexture);
        GUI.DrawTexture(new Rect(rect.x, rect.y + rect.height - 1f, rect.width, 1f), blankTexture);
        GUI.color = Color.white;
    }

    static public void HighlightLine(Color c, float height)
    {
        Rect rect = GUILayoutUtility.GetRect(Screen.width - 16f, height);
        GUILayout.Space(-height);
        c.a *= 0.3f;
        GUI.color = c;
        GUI.DrawTexture(rect, gradientTexture);
        c.r *= 0.5f;
        c.g *= 0.5f;
        c.b *= 0.5f;
        GUI.color = c;
        GUI.DrawTexture(new Rect(rect.x, rect.y + 1f, rect.width, 1f), blankTexture);
        GUI.DrawTexture(new Rect(rect.x, rect.y + rect.height - 1f, rect.width, 1f), blankTexture);
        GUI.color = Color.white;
    }

    static public void HighBackgroud(Color c, Rect rect)
    {
        GUI.color = c;
        GUI.DrawTexture(rect, blankTexture);
        GUI.color = new Color(0f, 0f, 0f, 0.25f);
        GUI.DrawTexture(new Rect(rect.x, rect.y, rect.width, 4f), blankTexture);
        GUI.DrawTexture(new Rect(rect.x, rect.y, 4f, rect.height), blankTexture);
        GUI.DrawTexture(new Rect(rect.x, rect.y + rect.height - 1f, rect.width, 4f), blankTexture);
        GUI.DrawTexture(new Rect(rect.x + rect.width, rect.y, 4f, rect.height + 3f), blankTexture);
        GUI.color = Color.white;
    }

    #endregion

    #region DataSave
    void Load()
    {
        XmlDocument documnet = new XmlDocument();
        TextAsset asset = Resources.Load("BundleData", typeof(TextAsset)) as TextAsset;
        if (asset == null)
            return;

        documnet.LoadXml(asset.text);

        XmlNode root = documnet.SelectSingleNode("Bundles");
        if (root == null || root.ChildNodes.Count == 0)
            return;

        XmlElement rootElement = root as XmlElement;
        m_PlatformRootDic.Clear();
        string rootPath = "";
        foreach (TargetPlatform platform in System.Enum.GetValues(typeof(TargetPlatform)))
        {
            rootPath = "RootDirectory_" + platform.ToString();
            if (rootElement.HasAttribute(rootPath))
            {
                m_PlatformRootDic.Add(platform, rootElement.GetAttribute(rootPath));
            }
        }
        if (m_PlatformRootDic.ContainsKey(m_TargetPlatform))
        {
            m_RootDirectory = m_PlatformRootDic[m_TargetPlatform];
        }

        foreach (XmlElement node in root.ChildNodes)
        {
            if (node == null)
                continue;

            if (node.Name == "Bundle")
            {
                BundleGroup bundle = new BundleGroup();
                bundle.m_BundleName = node.GetAttribute("Name");
                bundle.m_BundlePath = node.GetAttribute("Path");
                bundle.m_BundleType = (BundleType)System.Convert.ToInt32(node.GetAttribute("BundleType"));
                bundle.StringToAssets(node.GetAttribute("Assets"));
                bundle.m_Dependencies = node.GetAttribute("Dependency");
                bundle.m_Module = node.GetAttribute("Module");
                if (string.IsNullOrEmpty(bundle.m_Module))
                {
                    bundle.m_Module = bundle.m_BundleName;
                }
                string id = bundle.GetId();
                if (!m_BundleList.ContainsKey(id))
                {
                    m_BundleList.Add(id, bundle);
                }
            }
        }
    }

    void Save()
    {
        XmlDocument document = new XmlDocument();
        XmlDeclaration xmldec;
        xmldec = document.CreateXmlDeclaration("1.0", "UTF-8", "yes");
        document.AppendChild(xmldec);
        XmlElement rootNode = document.CreateElement("Bundles");

        if (m_PlatformRootDic.ContainsKey(m_TargetPlatform))
        {
            m_PlatformRootDic[m_TargetPlatform] = m_RootDirectory;
        }
        else
        {
            m_PlatformRootDic.Add(m_TargetPlatform, m_RootDirectory);
        }

        string rootPath = "";
        foreach (KeyValuePair<TargetPlatform, string> rootdir in m_PlatformRootDic)
        {
            rootPath = "RootDirectory_" + rootdir.Key.ToString();
            rootNode.SetAttribute(rootPath, rootdir.Value);
        }

        foreach (BundleGroup bundle in m_BundleList.Values)
        {
            XmlElement node = document.CreateElement("Bundle");

            XmlAttribute attribute = document.CreateAttribute("Name");
            attribute.InnerText = bundle.m_BundleName;
            node.Attributes.Append(attribute);

            attribute = document.CreateAttribute("Path");
            attribute.InnerText = bundle.m_BundlePath;
            node.Attributes.Append(attribute);

            attribute = document.CreateAttribute("BundleType");
            attribute.InnerText = ((int)bundle.m_BundleType).ToString();
            node.Attributes.Append(attribute);

            attribute = document.CreateAttribute("Assets");
            attribute.InnerText = bundle.AssetsToString();
            node.Attributes.Append(attribute);

            attribute = document.CreateAttribute("Dependency");
            attribute.InnerText = bundle.m_Dependencies;
            node.Attributes.Append(attribute);
            rootNode.AppendChild(node);
        }

        document.AppendChild(rootNode);
        string path = Application.dataPath + "/Resources/BundleData.xml";
        document.Save(path); AssetDatabase.Refresh();
    }
    #endregion

    #region save LoadAsset.xml
    void SaveLoadAsset()
    {
        if (m_BundleList.Count == 0)
            return;

        XmlDocument document = new XmlDocument();
        XmlDeclaration xmldec;
        xmldec = document.CreateXmlDeclaration("1.0", "UTF-8", "yes");
        document.AppendChild(xmldec);
        XmlElement rootNode = document.CreateElement("LoadAsset");

        XmlElement depends = document.CreateElement("Dependencies");
        XmlElement assets = document.CreateElement("Assets");
        foreach (BundleGroup bundle in m_BundleList.Values)
        {
            if (!string.IsNullOrEmpty(bundle.m_Dependencies))
            {
                XmlElement depend = document.CreateElement("Dependence");
                depend.SetAttribute("BundleID", bundle.GetId());
                depend.SetAttribute("DependenceID", bundle.m_Dependencies);
                depends.AppendChild(depend);
            }

            if (IsOtherDepend(bundle))
                continue;

            if (bundle.m_BundleType == BundleType.StreamedScenes)
                continue;

            foreach (Object o in bundle.m_AssetArray)
            {
                if (o.name.Equals("LoadAsset"))
                    continue;

                XmlElement asset = document.CreateElement("Asset");
                asset.SetAttribute("Name", o.name);
                asset.SetAttribute("AType", GetObjectType(o));
                asset.SetAttribute("Path", bundle.m_BundlePath);
                asset.SetAttribute("Bundle", bundle.m_BundleName);
                asset.SetAttribute("Module", bundle.m_Module);
                asset.SetAttribute("Need", "true");
                assets.AppendChild(asset);
            }
        }

        rootNode.AppendChild(depends);
        rootNode.AppendChild(assets);
        document.AppendChild(rootNode);
        string path = Application.dataPath;
        path = EditorUtility.OpenFolderPanel("Save LoadAsset", path, "Resources");
        if (path != null && path.Length > 0)
        {
            document.Save(path + "/LoadAsset.xml");
            AssetDatabase.Refresh();
        }
    }

    #endregion

    private bool IsOtherDepend(BundleGroup bundle)
    {
        foreach (BundleGroup other in m_BundleList.Values)
        {
            if (other.Equals(bundle))
                continue;

            if (other.m_Dependencies.Equals(bundle.GetId()))
                return true;
        }

        return false;
    }

    private string GetObjectType(Object o)
    {
        string typeStr = o.GetType().ToString();
        return typeStr.Substring(12);
    }

    private void Refresh()
    {
        if (m_BundleList.Count == 0)
            return;

        foreach (BundleGroup bundle in m_BundleList.Values)
        {
            if (File.Exists(GetPath(bundle)))
            {
                bundle.m_IsExsit = true;
            }
            else
            {
                bundle.m_IsExsit = false;
            }
        }
    }
}

public class BundleGroup
{
    public string m_BundleName = "";
    public string m_BundlePath = "";
    public BundleType m_BundleType = BundleType.StreamedAssets;
    public Object m_MainAsset;
    public List<Object> m_AssetArray = new List<Object>();
    public string m_Dependencies = "";
    public string m_Module = "";
    public bool m_IsBuild = true;
    public bool m_IsExsit = false;
    public bool m_IsError = false;

    public BundleGroup()
    {

    }

    public BundleGroup(BundleGroup bundle)
    {
        m_BundleName = bundle.m_BundleName;
        m_BundlePath = bundle.m_BundlePath;
        m_BundleType = bundle.m_BundleType;
        m_MainAsset = bundle.m_MainAsset;
        m_AssetArray = bundle.m_AssetArray;
        m_Dependencies = bundle.m_Dependencies;
        m_Module = bundle.m_Module;
    }

    public void StringToAssets(string str)
    {
        if (string.IsNullOrEmpty(str))
            return;

        string[] strArray = str.Split(';');
        for (int i = 0; i < strArray.Length; i++)
        {
            Object o = AssetDatabase.LoadMainAssetAtPath(strArray[i]);
            if (o == null)
            {
                EditorUtility.DisplayDialog("Missing Object", strArray[i] + " is missing!", "Ok");
                m_IsError = true;
            }
            else
            {
                m_AssetArray.Add(o);
            }
        }
    }

    public string AssetsToString()
    {
        string assets = "";
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < m_AssetArray.Count; i++)
        {
            builder.Append(AssetDatabase.GetAssetPath(m_AssetArray[i]));
            builder.Append(';');
        }

        if (builder.Length > 0)
        {
            builder.Remove(builder.Length - 1, 1);
            assets = builder.ToString();
        }

        return assets;
    }

    public string GetId()
    {
        return m_BundlePath + "/" + m_BundleName;
    }
}
public enum BundleType
{
    StreamedAssets = 1,
    StreamedScenes,
}